package com.ztesoft.web.common.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import com.ztesoft.core.common.Page;
import com.ztesoft.core.convert.IArgConversionService;
import com.ztesoft.core.db.ds.DynamicDataSourceManager;
import com.ztesoft.core.idproduce.ISequenceGenerator;
import com.ztesoft.framework.exception.BaseAppException;
import com.ztesoft.framework.exception.ExceptionHandler;
import com.ztesoft.framework.log.ZTEsoftLogManager;
import com.ztesoft.framework.util.Utils;
import com.ztesoft.web.baseconfig.db.arg.DmPlanArg;
import com.ztesoft.web.baseconfig.db.arg.DmPlanArg.DmPlanCriteria;
import com.ztesoft.web.baseconfig.db.dao.DmPlanDao;
import com.ztesoft.web.baseconfig.db.dao.DmSrcTableDao;
import com.ztesoft.web.baseconfig.db.po.DmSrcTablePO;
import com.ztesoft.web.baseconfig.service.IDmSrcTableService;
import com.ztesoft.web.common.db.arg.SysModuleArg;
import com.ztesoft.web.common.db.arg.SysModuleArg.SysModuleCriteria;
import com.ztesoft.web.common.db.dao.OperationLogDao;
import com.ztesoft.web.common.db.dao.SysModuleDao;
import com.ztesoft.web.common.db.po.DbBaseInfoPO;
import com.ztesoft.web.common.db.po.OperationLogPO;
import com.ztesoft.web.common.db.po.ProcedureDataPO;
import com.ztesoft.web.common.db.po.SysModuleNodePO;
import com.ztesoft.web.common.db.po.SysModulePO;
import com.ztesoft.web.common.service.ISysModuleService;
import com.ztesoft.web.syncbaseinfo.service.BaseInfoService;

/**
 * <Description> <br>
 * 
 * @author lin.jie<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2015年8月4日 <br>
 * @since V1.0<br>
 * @see com.ztesoft.web.baseconfig.service.impl <br>
 */

@Service("sysModuleService")
public class SysModuleServiceImpl implements ISysModuleService {

	private static final ZTEsoftLogManager logger = ZTEsoftLogManager.getLogger(SysModuleServiceImpl.class);

	@Autowired
	private SysModuleDao sysModuleDao;
	@Autowired
	private OperationLogDao operationLogDao;
	@Autowired
	private DmPlanDao dmPlanDao;
	@Autowired
	private DmSrcTableDao dmSrcTableDao;
	@Autowired
	private IDmSrcTableService dmSrcTableService;
	@Autowired
	private BaseInfoService baseInfoService;
	/**
	 * 查询条件转换成Arg类的服务接口
	 */
	@Resource(name = "defaultArgConversionService")
	private IArgConversionService argConversionService;

	/**
	 * 主键生成器
	 */
	@Resource(name = "sequenceProcGenerator")
	private ISequenceGenerator sequenceGenerator;

	@Override
	public SysModuleNodePO[] queryAllForTree() throws BaseAppException {
		List<SysModuleNodePO> resultList = sysModuleDao.queryAllForTree();
		logger.debug("queryAllForTree : selectList = {0}", resultList);
		return resultList.toArray(new SysModuleNodePO[0]);
	}
	@Override
	 public ProcedureDataPO[] queryAllProForDbLinkId(Integer dbLinkId, String dbUserName) throws BaseAppException {
		List<DmSrcTablePO> srcList = new ArrayList<DmSrcTablePO>();
		List<ProcedureDataPO> resultList = new ArrayList<ProcedureDataPO>();
		try {
			srcList = dmSrcTableService.findProcedureInfo(dbLinkId, dbUserName);
			for (DmSrcTablePO dmSrcTablePO : srcList) {
				ProcedureDataPO po = new ProcedureDataPO();
				po.setObjectId(dmSrcTablePO.getProcedureName());
				po.setObjectName(dmSrcTablePO.getProcedureName());
				resultList.add(po);
			}
			logger.debug("queryAllForTree : selectList = {0}", resultList);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultList.toArray(new ProcedureDataPO[0]);
	}
	
	@Override
	 public Map<String, String> qryInfoByDbLinkId(Integer dbLinkId) throws BaseAppException{
		DmSrcTablePO table = dmSrcTableDao.selectByDbLinkId(dbLinkId);
		List<DmSrcTablePO> srcList = new ArrayList<DmSrcTablePO>();
		Map<String, String> returnData = new HashMap<String, String>();
		try {
			returnData = dmSrcTableService.qryInfoByDbLinkId(dbLinkId, table.getDbUserName(), table.getTableName());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return returnData;
	}
	@Override
    public SysModulePO selectByPrimaryKey(Integer key) throws BaseAppException {
        // ///////
        // TODO 根据业务场景，设置查询条件、数据校验等

        // ///////
        return sysModuleDao.selectByPrimaryKey(key);
    }

    @Override
    public List<SysModulePO> selectByArg(SysModulePO record) throws BaseAppException {
        logger.debug("selectByArg begin...record={0}", record);

        // 第一种方式：自己创建arg，自行设置查询条件及操作符
        //SysModuleArg arg = new SysModuleArg();
        //SysModuleCriteria criteria = arg.createCriteria();
        
        // 第二种方式：利用arg转换服务，转换出arg，带上查询条件及操作符，
        // 转换后，还可以自行对arg进行设置修改
        SysModuleArg arg = argConversionService.invokeArg(SysModuleArg.class, record);

        // ///////
        // TODO 根据业务场景，设置查询条件，示例
        // if (Utils.notEmpty(record.getUserName())) {
        // criteria.andUserNameLike(record.getUserName());
        // }
        // ///////

        return sysModuleDao.selectByArg(arg);
    }

    @Override
    public Page<SysModulePO> selectByArgAndPage(SysModulePO record, Page<SysModulePO> resultPage)
            throws BaseAppException {
        logger.debug("selectByArgAndPage begin...record={0}", record);

        // 第一种方式：自己创建arg，自行设置查询条件及操作符
        // SysModuleArg arg = new SysModuleArg();
        // //TODO 根据业务场景，设置查询条件，示例
        // SysModuleCriteria criteria = arg.createCriteria();
        // if (Utils.notEmpty(record.getUserName())) {
        // criteria.andUserNameLike(record.getUserName());
        // }

        // 第二种方式：利用arg转换服务，转换出arg，带上查询条件及操作符，
        // 转换后，还可以自行对arg进行设置修改
        SysModuleArg arg = argConversionService.invokeArg(SysModuleArg.class, record);

        resultPage = sysModuleDao.selectByArgAndPage(arg, resultPage);


        return resultPage;
    }
    
	//系统模块维护查询
    @Override
    public Page<SysModulePO> selectByArgAndPageSys(SysModulePO record, Page<SysModulePO> resultPage)
    		throws BaseAppException {
    	logger.debug("selectByArgAndPage begin...record={0}", record);
    	
    	// 第一种方式：自己创建arg，自行设置查询条件及操作符
    	 SysModuleArg arg = new SysModuleArg();
    	 //TODO 根据业务场景，设置查询条件，示例
    	 SysModuleCriteria criteria = arg.createCriteria();
    	 if (Utils.notEmpty(record.getModuleName())) {
    	 criteria.andModuleNameLike(record.getModuleName());
    	 }
    	 if (Utils.notEmpty(record.getParentModuleId())) {
    		 criteria.andParentModuleIdEqualTo(record.getParentModuleId());
    	 }
    	 if (Utils.notEmpty(record.getModuleLevel())) {
    		 criteria.andModuleLevelEqualTo(record.getModuleLevel());
    	 }
    	
    	// 第二种方式：利用arg转换服务，转换出arg，带上查询条件及操作符，
    	// 转换后，还可以自行对arg进行设置修改
//    	SysModuleArg arg = argConversionService.invokeArg(SysModuleArg.class, record);
    	
    	resultPage = sysModuleDao.selectByArgAndPageSys(arg, resultPage);
    	
    	
    	return resultPage;
    }
	//系统模块维护 添加
    @Override
    public int add(SysModulePO record) throws BaseAppException {
        logger.debug("add begin...record={0}", record);
        int num=0;
        List<SysModulePO> SysList = sysModuleDao.selectByModuleName(record.getParentModuleId());	//系统模块维护 是否有相同的模块名
        for(SysModulePO Dmp:SysList){
        	if(record.getModuleName().equals(Dmp.getModuleName())){
        		num=num+1;
        	}
        }
        if (num != 0) {// 存在相同名称的模块，不可以新增
        	record.setModuleId(0);
			return 0;
		} else {
	        // ///////
	        // TODO 根据业务场景，进行重名校验、设置主键、设置属性默认值等
	        // 获取主键
	         int pkId = sequenceGenerator.sequenceIntValue("SYS_MODULE","module_id");
	         record.setModuleId(pkId);
	         record.setCreateDate(new Date());
	         record.setStaffId(record.getStaffId());
	         if(record.getParentModuleId()==0){
	        	 record.setModuleLevel(0);//根节点：pid=0，level=0
	         }else{
		         SysModulePO  PLevelPo= sysModuleDao.selectByParentModuleId(record.getParentModuleId());//修改后新数据的父节点 level
		         record.setModuleLevel(PLevelPo.getModuleLevel()+1);//修改后新数据的level
	         }
	         ///////
	         int log =sysModuleDao.insertSelective(record);
	         System.out.println(log);
	         if(log>0){
	        	 OperationLogPO po =new OperationLogPO();
	        	 //获取主键
	              int pkId1 = sequenceGenerator.sequenceIntValue("OPERATION_LOG","LOG_ID");
	              po.setLogId(pkId1);
	              po.setStaffId(record.getStaffId());
	              po.setOpModule("系统目录维护-添加");
	              po.setOpType(1);
	              po.setOpDesc("进行系统目录维护的添加操作");
	              po.setOpDate(new Date());
	              po.setLogType(1);
	              po.setLogLevel(1);
	              operationLogDao.insertSelective(po);
	         }
	        return log;
		}
    }
  //系统模块维护 修改
    @Override
    public int update(SysModulePO record) throws BaseAppException {
        logger.debug("update begin...record={0}", record);
        // ///////
        // TODO 根据业务场景，进行重名校验、数据有效性校验、设置属性默认值等
////        record.setModuleLevel(record.getParentModuleId()+1);
       
        SysModulePO  OldLevelPo = sysModuleDao.selectById(record.getModuleId());//当前修改数据原本的level
        if(OldLevelPo==null){//节点不存在的时候，返回前台提示
        	record.setModuleId(0);
        	return 0;
        }else{
        	//重名判断——开始
        	 int num=0;
             List<SysModulePO> SysList = sysModuleDao.selectByModuleName(record.getParentModuleId());	//系统模块维护 是否有相同的模块名
             for(SysModulePO Dmp:SysList){
             	if(record.getModuleName().equals(Dmp.getModuleName())){
             		num=num+1;
             	}
             }
             if (num != 0) {// 存在相同名称的模块，不可以新增
             	record.setModuleId(-1);
     			return 0;
             }
           //重名判断——结束
	        int Lvl;
	        //判断修改节点死循环 遍历需要的节点——开始
		       List<Integer> resultIdList1 = new ArrayList<Integer>();//删除id
		       List<Integer> idList1 = new ArrayList<Integer>();//查找id
		       idList1.add(record.getModuleId());//作父节点去查
		       List<SysModulePO> sysModulePOList1  = null;
			        while(true) {
			        	 if (idList1.size() == 0) break;
			        	 SysModuleArg arg = new SysModuleArg();
			        	 //TODO 根据业务场景，设置查询条件，示例
			        	 SysModuleCriteria criteria = arg.createCriteria();
			        	 criteria.andParentModuleIdIn(idList1);
			             sysModulePOList1 =sysModuleDao.selectByParentModuleIdTree(arg);//IN idList
			        	 if (sysModulePOList1.size() == 0) {//加外部传入的值
			        		 resultIdList1.add(record.getModuleId());
			        		 break;
			        	 } else {
			        		 idList1 = new ArrayList<Integer>();//id
			        		 for (SysModulePO po : sysModulePOList1)  {
			        			 resultIdList1.add(po.getModuleId());// 放到list1
			        			 idList1.add(po.getModuleId());
			        		 }
			        	 }
			        }
			        for(Integer Dmp:resultIdList1){
		             	if(record.getParentModuleId().equals(Dmp)){
		             		num=num+1;
		             	}
		             }
			        if (num != 0) {//判断修改节点死循环
		             	record.setModuleId(-2);
		     			return 0;
		             }
		      //判断修改节点死循环 遍历需要的节点——结束
	        if(record.getParentModuleId()==0){
	        	record.setModuleLevel(0); 
	        	Lvl=0-OldLevelPo.getModuleLevel();//新lvl和就lvl的差
	        }else{
	        	SysModulePO  PLevelPo = sysModuleDao.selectByParentModuleId(record.getParentModuleId());//修改后新数据的父节点 level
	        	record.setModuleLevel(PLevelPo.getModuleLevel()+1);//修改后新数据的level
	        	Lvl=PLevelPo.getModuleLevel()+1-OldLevelPo.getModuleLevel();//新lvl和就lvl的差
	        }
	        int log =sysModuleDao.updateByPrimaryKeySelective(record);//修改当前数据的lvl，pid
	        //遍历需要修改的子集——开始
	        List<Integer> resultIdList = new ArrayList<Integer>();//修改子集id
	        List<Integer> idList = new ArrayList<Integer>();//查找id
	        idList.add(record.getModuleId());//作父节点去查
	        List<SysModulePO> sysModulePOList  = null;
	         while(true) {
	         	 if (idList.size() == 0) break;
	         	 SysModuleArg arg = new SysModuleArg();
	         	 //TODO 根据业务场景，设置查询条件，示例
	         	 SysModuleCriteria criteria = arg.createCriteria();
	         	 criteria.andParentModuleIdIn(idList);
	         	 sysModulePOList =sysModuleDao.selectByParentModuleIdTree(arg);//IN idList
	         	 if (sysModulePOList.size() == 0) {//没有子节点时跳出
	         		 break;
	         	 } else {
	         		 idList = new ArrayList<Integer>();//id
	         		 for (SysModulePO po : sysModulePOList)  {
	         			 resultIdList.add(po.getModuleId());// 放到resultIdList
	         			 idList.add(po.getModuleId());
	         		 }
	         	 }
	         }
	       //遍历需要修改的子集——结束
				if (Lvl != 0) {// lvl差不等于0的才需要修改子集的level
					record.setLevel(Lvl);
					SysModuleArg argupd = new SysModuleArg();
					// TODO 根据业务场景，设置查询条件，示例
					SysModuleCriteria criteria = argupd.createCriteria();
					if (Utils.notEmpty(resultIdList)) {
						criteria.andModuleIdIn(resultIdList);
						sysModuleDao.updateByArg(record, argupd);
					}
				}
	        // ///////
	        System.out.println(log);
				if (log > 0) {
					OperationLogPO po = new OperationLogPO();
					// 获取主键
					int pkId1 = sequenceGenerator.sequenceIntValue("OPERATION_LOG","LOG_ID");
					po.setLogId(pkId1);
					po.setStaffId(record.getStaffId());
					po.setOpModule("系统目录维护-修改");
					po.setOpType(3);
					po.setOpDesc("进行系统目录维护的修改操作");
					po.setOpDate(new Date());
					po.setLogType(1);
					po.setLogLevel(1);
					operationLogDao.insertSelective(po);
				}
			return log;
        }
    }
    

  //系统模块维护 删除
    @Override
    public int delete(SysModulePO record) throws BaseAppException {
        logger.debug("delete begin...record={0}", record);
        SysModulePO  OldLevelPo = sysModuleDao.selectById(record.getModuleId());//当前修改数据原本的level
        int isPlan = dmPlanDao.selectByNodeId(record.getModuleId());//判断该NodeId是否已经被创建
        if(OldLevelPo==null){//节点不存在的时候，返回前台提示
        	return 0;
        }else if (isPlan>0){
        	return -1;
        }else{
	        //遍历需要删除的节点——开始
	       List<Integer> resultIdList = new ArrayList<Integer>();//删除id
	       List<Integer> idList = new ArrayList<Integer>();//查找id
	       idList.add(record.getModuleId());//作父节点去查
	       List<SysModulePO> sysModulePOList  = null;
		        while(true) {
		        	 if (idList.size() == 0) break;
		        	 SysModuleArg arg = new SysModuleArg();
		        	 //TODO 根据业务场景，设置查询条件，示例
		        	 SysModuleCriteria criteria = arg.createCriteria();
		        	 criteria.andParentModuleIdIn(idList);
		             sysModulePOList =sysModuleDao.selectByParentModuleIdTree(arg);//IN idList
		        	 if (sysModulePOList.size() == 0) {//加外部传入的值
		        		 resultIdList.add(record.getModuleId());
		        		 break;
		        	 } else {
		        		 idList = new ArrayList<Integer>();//id
		        		 for (SysModulePO po : sysModulePOList)  {
		        			 resultIdList.add(po.getModuleId());// 放到list1
		        			 idList.add(po.getModuleId());
		        		 }
		        	 }
		        }
	      //遍历需要删除的节点——结束
		    for(Integer moduleIdList:resultIdList){//判断该NodeId是否已经被创建
		    	int isPlans = dmPlanDao.selectByNodeId(moduleIdList);
		    	if(isPlans>0){
		    		return -1;
		    	}
		    }
			SysModuleArg argdel = new SysModuleArg();
			//TODO 根据业务场景，设置查询条件，示例
			SysModuleCriteria criteria = argdel.createCriteria();
			criteria.andModuleIdIn(resultIdList);
			int log = sysModuleDao.deleteByArg(argdel);//in（resultIdList）
			System.out.println(log);
			if(log>0){
			   	 OperationLogPO po =new OperationLogPO();
			   	 //获取主键
			     int pkId1 = sequenceGenerator.sequenceIntValue("OPERATION_LOG","LOG_ID");
			     po.setLogId(pkId1);
			     po.setStaffId(record.getStaffId());
			     po.setOpModule("系统目录维护-删除");
			     po.setOpType(2);
			     po.setOpDesc("进行系统目录维护的删除操作");
			     po.setOpDate(new Date());
			     po.setLogType(1);
			     po.setLogLevel(1);
			     operationLogDao.insertSelective(po);
				}
			return log;
        }
    }
	@Override
	public List<SysModulePO> searchSysmodule()  throws BaseAppException{
		logger.debug("Select module_id,module_name from sys_module where module_level=0");
		SysModuleArg arg = new SysModuleArg();
		SysModuleArg.SysModuleCriteria c = arg.createCriteria();
		c.andModuleLevelEqualTo(0);
		return sysModuleDao.selectByArg(arg);
	}
	
	@Autowired
	private DynamicDataSourceManager dynamicDataSourceManager;
	
	@Override
	public boolean isExistProcedure(Integer dbBaseId, String dbUserName, String produreName) throws BaseAppException {
		String sql = "";
		DataSource ds = null;
		try {
			String[] dbConfig = null;
			int count = 0;
			dbConfig = baseInfoService.getDbConfig(dbBaseId, dbUserName);
			ds = dynamicDataSourceManager.getDruidDataSource(dbBaseId + dbUserName, dbConfig);
			if ("oracle".equals(dbConfig[0])) {
				sql = "select count(*) from user_objects where object_type='PROCEDURE' and object_name = ?";
				produreName = StringUtils.upperCase(produreName);
				count = new JdbcTemplate(ds).queryForObject(sql, Integer.class, produreName);
			}
			if ("informix".equals(dbConfig[0])) {
				sql = "select count(*) from SYSPROCEDURES where procname = ?";
				count = new JdbcTemplate(ds).queryForObject(sql, Integer.class, produreName);
			}
			if ("mysql".equals(dbConfig[0])) {
				sql = "select count(*) from mysql.proc where name = ? and db = ?";
				count = new JdbcTemplate(ds).queryForObject(sql, Integer.class, produreName, dbConfig[3]);
			}
			return count > 0 ? true : false;
		} catch (Exception e) {
			logger.error(e);
			throw ExceptionHandler.publish("", "执行存储过程查询异常:"+sql, e);
		} 
	}
	
	@Override
	public boolean isExistPartitions(Integer dbBaseId, String dbUserName, String tableName) throws BaseAppException {
		String sql = "";
		boolean flag = false;
		String[] dbConfig = baseInfoService.getDbConfig(dbBaseId, dbUserName);
		DataSource ds = dynamicDataSourceManager.getDruidDataSource(dbBaseId + dbUserName, dbConfig);
		if ("oracle".equals(dbConfig[0])) {
			sql = "SELECT count(*) FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = ? ";
			tableName = StringUtils.upperCase(tableName);
			int count = new JdbcTemplate(ds).queryForObject(sql, Integer.class, tableName);
			if (count > 0) {
				flag = true;
			} else {
				throw ExceptionHandler.publish(tableName+"不存在分区,请选择条件归档方式!"); 
			}
		} else if ("informix".equals(dbConfig[0]) || "mysql".equals(dbConfig[0])) {
			throw ExceptionHandler.publish("分区归档只支持oracle数据库");
		}
		return flag;
	}
}
